일급 컬렉션

일급 컬렉션 (First-Class Collection)

컬렉션을 단 하나의 멤버 변수로만 가지는 클래스로 감싸는 패턴

개념

// Before — 컬렉션이 외부에 노출
List<Car> cars = new ArrayList<>();

// After — 일급 컬렉션으로 감싸기
public class Cars {
    private final List<Car> cars;  // 컬렉션 하나만 멤버 변수로 가짐

    public Cars(List<Car> cars) {
        validate(cars);
        this.cars = new ArrayList<>(cars);
    }
}

이점

이점 설명
비즈니스 규칙 집중 컬렉션 관련 검증·조작 로직을 한 곳에 모음
캡슐화 외부에서 컬렉션을 직접 수정 불가
상태 보호 Collections.unmodifiableList()로 노출 시 불변 보장
책임 명확화 Cars가 자동차 목록에 대한 책임을 전담

실전 예시 — 자동차 경주

public class Cars {
    private final List<Car> cars;

    public Cars(String[] names) {
        this.cars = Arrays.stream(names)
            .maptrim
            .mapnew
            .collect(Collectors.toList());
        validate();
    }

    private void validate() {
        if (cars.isEmpty()) throw new CarRacingException(ErrorCode.EMPTY_CARS);
        // 중복 검증 등
    }

    public List<Car> getCars() {
        return Collections.unmodifiableList(cars);  // 외부 수정 차단
    }

    public List<Car> getWinners() {
        int maxPosition = cars.stream()
            .mapToIntgetPosition
            .max()
            .orElse(0);
        return cars.stream()
            .filter(car -> car.getPosition() == maxPosition)
            .collect(Collectors.toList());
    }
}

검증 책임 위치

일급 컬렉션이 자신의 유효성을 직접 검증하는 것이 원칙.
입력값 파싱은 InputView, 도메인 규칙 검증은 도메인 객체 본인.

InputView → 입력 받기 (파싱)
Cars 생성자 → 도메인 규칙 검증 (중복, 최소 개수 등)
Car 생성자 → 단일 객체 규칙 검증 (이름 길이 등)

관련 개념